import * as THREE from 'three';
import Stat from 'three/examples/jsm/libs/stats.module'
import { CSS2DObject, CSS2DRenderer } from './CSS2DRenderer'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import ColladaLoader from './ColladaLoader'
import { Mesh } from 'three';
import sun from './sun-angle';
import { Group } from 'three';

// 颜色常量
const width = window.innerWidth; //窗口宽度
var height = window.innerHeight - $('#date-controller').height(); //窗口高度
var color8 = new THREE.Color(0x5CEE99); //代表日照时长在8以上用的颜色
var color6 = new THREE.Color(0xB7EF7D);
var color4 = new THREE.Color(0xF9FE74);
var color2 = new THREE.Color(0xFCC87F);
var color0 = new THREE.Color(0xF15E8F);
let fillStyleMap = {
    '自持': '#cccccc',
    '公寓': '#cccccc',
    '公租': '#cccccc',
    '物业': '#cccccc',
    '商业': '#cccccc',
    '办公': '#cccccc',
    '已开': '#cccccc',
    '未开': '#bcdabe',
    '预计': '#4da5ff',
    '本期': '#fdab71'

}
let buildUnitMap //新增map
let trueLightOrient
const timeToColor = (lightTime) => {

    if (lightTime == 8.0) {
        return color8;
    } else if (lightTime > 6) {
        return color6;
    } else if (lightTime > 4) {
        return color4;
    } else if (lightTime > 2) {
        return color2;
    } else {
        return color0;
    }
}
function correctArr(numStrArr) { //修改处5，新增方法，对特殊数组处理
    if (numStrArr.length == 5) { //数组有5个元素时前两个数字代表楼号
        numStrArr[0] = numStrArr[0] + "-" + numStrArr[1]
        numStrArr[1] = numStrArr[2]
        numStrArr[2] = numStrArr[3]
        numStrArr[3] = numStrArr[4]
    }
    return numStrArr
}
export default class ThreePresenter {
    latitude = 30.26667
    longitude = 120.20000
    clock = null
    renderer = null
    controls = null
    light = null
    scene = null
    plane = null
    ameLight = null
    camera = null
    _flag = -1
    start = -1
    end = 61
    lastDate = null
    stat = null
    _frameHandler = null
    labelRenderer = null
    dx = 0
    dy = 0
    fov = 50
    near = 1
    fear = 3000
    groupArr = []
    colorJson = null
    loadUrl = null
    colorUrl = null
    mesh = null
    initTerm = '大寒'
    callFinish = null
    debug = false
    loader = null
    // groupArr = 
    constructor(start, end) {
        this.start = start
        this.end = end
        this.scene = new THREE.Scene();

    }
    changeSE(s, e) {
        this.start = s
        this.end = e
    }

    changeDaeLoad(url) {
        if (this.mesh) {
            this.scene.clear()
            this.cancelAnim()
        }
        this._loadDae(url)
        this.scene.add(this.light)
        this.scene.add(this.ameLight)
        this.scene.add(this.plane)

    }
    //切换模型颜色的季节
    changeTerm(index) {
        console.log("changeTerm", index)
        if (!this.colorUrl) return
        const json = this.colorJson
        const groupArr = this.mesh.children[0].children
        let color
        let colors = [];
        let normals;
        let numStrArr
        let vertexMaterial = new THREE.MeshLambertMaterial({
            side: THREE.FrontSide, //两个三角面均可见
            vertexColors: true,
        }); //材质对象
        vertexMaterial.opacity = 1
        vertexMaterial.transparent = false
        vertexMaterial.side = 0
        vertexMaterial.receiveShadow = true
        vertexMaterial.castShadow = true
        let season = index
        if (season == '春秋分') {
            season = '春分'
        }
        // switch (index) {
        //     case 0: season = '大寒'; break;
        //     case 1: season = '冬至'; break;
        //     case 2: season = '春分'; break;
        //     case 3: season = '夏至'; break;

        // }
        let arr
        let sideColor
        let houseData
        let lightTime
        let flag = false
        for (let a = 0; a < groupArr.length; a++) {
            if (groupArr[a].name.search("-") != -1) { //筛选出name包含"-"的元素
                numStrArr = correctArr(groupArr[a].name.replace("_","").split("-"))
                try {
                    normals = groupArr[a].children[0].geometry.attributes.normal.array //每个顶点所在面的法向量数组，每3个数字表示一个顶点
                    colors = new Array(normals.length); //颜色数组数量需要和顶点个数保持一致，每3个数字表示一个颜色
                    colors.fill(0.6) //楼面默认填充灰色
                    sideColor = null
                    arr = json.data.find(item => item.name === numStrArr[0] + "#").data.reduce(function (a, b) { return a.concat(b) }); //二维数组变一维数组
                    houseData = arr[buildUnitMap.get(numStrArr[0]).indexOf(numStrArr[1] + "-" + numStrArr[2])][parseInt(numStrArr[3]) - 1] //先通过楼号从hash表中拿到数组，name中间两个数字在数组的索引就代表第几列
                    if (houseData != null && houseData[season] != null) {
                        switch (season) {
                            case "春分":
                                lightTime = houseData.春分  //日照时间，数字依次表示楼号，单元，室，楼层
                                break;
                            case "大寒":
                                lightTime = houseData.大寒  //日照时间，数字依次表示楼号，单元，室，楼层
                                break;
                            case "夏至":
                                lightTime = houseData.夏至
                                if (houseData.侧面夏至 != undefined) {
                                    sideColor = timeToColor(houseData.侧面夏至)
                                }
                                break;
                            case "冬至":
                                lightTime = houseData.冬至
                                if (houseData.侧面冬至 != undefined) {
                                    sideColor = timeToColor(houseData.侧面冬至)
                                }
                                break;
                        }
                        color = timeToColor(lightTime)
                        // console.log("normals", trueLightOrient)

                        if (trueLightOrient.get(numStrArr[0]) === undefined) { //数组中没有这栋楼说明朝向正常
                            for (let i = 0; i < normals.length; i += 3) {
                                // console.log(normals.slice(i, i + 3).toString())
                                if (Math.abs(normals[i + 1] + 1) < 0.292) { //normals[i+1]≈-1的向量代表南面
                                    colors[i] = color.r
                                    colors[i + 1] = color.g
                                    colors[i + 2] = color.b
                                } else if (Math.abs(normals[i] + 1) < 0.292 || Math.abs(normals[i] - 1) < 0.292) { //normals[i]≈-1或1的向量代表侧面
                                    if (sideColor != null) {
                                        colors[i] = sideColor.r
                                        colors[i + 1] = sideColor.g
                                        colors[i + 2] = sideColor.b
                                    }
                                }
                            }
                        } else {
                            if (trueLightOrient.get(numStrArr[0]) == "西") { //南偏西大于45度的情况
                                for (let i = 0; i < normals.length; i += 3) {
                                    if (Math.abs(normals[i] + 1) < 0.292) {
                                        colors[i] = color.r
                                        colors[i + 1] = color.g
                                        colors[i + 2] = color.b
                                    } else if (Math.abs(normals[i + 1] + 1) < 0.292 || Math.abs(normals[i + 1] - 1) < 0.292) {
                                        if (sideColor != null) {
                                            colors[i] = sideColor.r
                                            colors[i + 1] = sideColor.g
                                            colors[i + 2] = sideColor.b
                                        }
                                    }
                                }
                            } else { //南偏东大于45度的情况
                                for (let i = 0; i < normals.length; i += 3) {
                                    if (Math.abs(normals[i] - 1) < 0.292) {
                                        colors[i] = color.r
                                        colors[i + 1] = color.g
                                        colors[i + 2] = color.b
                                    } else if (Math.abs(normals[i + 1] + 1) < 0.292 || Math.abs(normals[i + 1] - 1) < 0.292) {
                                        if (sideColor != null) {
                                            colors[i] = sideColor.r
                                            colors[i + 1] = sideColor.g
                                            colors[i + 2] = sideColor.b
                                        }
                                    }
                                }
                            }
                        }

                        groupArr[a].children[0].geometry.attributes.color = new THREE.Float32BufferAttribute(colors, 3);
                        // 三角面(网格)渲染模式
                        groupArr[a].children[0].material = vertexMaterial
                    } else {
                        groupArr[a].children[0].geometry.attributes.color = new THREE.Float32BufferAttribute([], 3);

                    }
                } catch (e) {
                    continue
                }

            }
        }


        //reset 模型
        this.renderer.info.reset()
        // this.scene.remove(this.mesh)
        // this.scene.refresh()
        // this.scene.add(this.mesh)
    }

    _loadDae(url) {
        this.loadUrl = url
        // 添加模型
        this.loader.load(url, result => {
            let mesh = result.scene
            this.mesh = mesh
            let scaleNum = 0.04
            let box = new THREE.Box3().setFromObject(mesh);  // 定位  
            // console.log(box)
            //轴对齐
            //居中
            mesh.rotation.x = - 0 / 180 * Math.PI //x轴对齐
            mesh.rotation.y = - 0 / 180 * Math.PI
            mesh.rotation.z = 90 / 180 * Math.PI
            //注意：模型绕x旋转了，所以此时计算y的位移时，应该使用z轴来运算
            let mdwid = box.max.x - box.min.x;
            let mdHei = box.max.z - box.min.z;
            // let mdlen = box.max.y - box.min.y;
            // //位移
            this.dy = mdwid / 2 + box.min.x
            this.dx = mdHei / 2 + box.min.z
            // this.dx = 250
            // this.dy = 400
            // console.log(box, this.dx, this.dy)
            mesh.position.set(-this.dx, -this.dy)


            // mesh.position.set( mdlen/ 2 + box.min.y, -mdwid / 2 + box.min.y)
            // mesh.position.set(- mdwid * scaleNum / 2 + 180, -mdlen * scaleNum / 2 + 180, 0)
            // mesh.scale.set(scaleNum, scaleNum, scaleNum);
            // mesh.castShadow = true
            // console.log(mesh)
            // console.log(mesh.children[0].children[1] instanceof Mesh)
            // console.log(mesh)
            // mesh.receiveShadow = true

            mesh.children[0].receiveShadow = true
            this.groupArr = result.scene.children[0].children
            this.scene.add(this.mesh)
            const { colorUrl } = this
            if (colorUrl) {
                let promise
                if (!this.colorJson) {
                    promise = fetch(colorUrl)
                } else {
                    promise = new Promise((r) => r(this.colorJson))
                }
                promise.then(async res => {
                    if (!this.colorJson) {
                        this.colorJson = await res.json()
                    }
                    const json = this.colorJson
                    trueLightOrient = new Map() //实际光照面朝向的散列表，只添加非南面
                    try {
                        buildTopFloors.forEach(function (value, key) {
                            let str = json.data.find(item => item.name === key + "#").angle.substring(3)
                            if (parseFloat(str.substr(0, str.length - 1)) > 45) {
                                trueLightOrient.set(key, json.data.find(item => item.name === key + "#").angle[2])
                            }
                        })
                    } catch (e) {

                    }

                    this.changeTerm(this.initTerm)

                    for (let item of mesh.children[0].children) {
                        // console.log(item)

                        if (item instanceof Group) {
                            item.children.forEach(ii => {
                                if (ii instanceof Mesh) {
                                    // console.log(item.material)
                                    // ii.material.shadowSide = THREE.BackSide
                                    // item.material.depthTest = false
                                    // ii.material.depthWrite = true
                                    ii.castShadow = true
                                    ii.receiveShadow = true
                                    ii.material.opacity = 1
                                    ii.material.transparent = false
                                }
                            })

                            // console.log(item.position)
                            // item.frustumCulled = false;
                            // item.material.emissive =  item.material.color;
                            // item.material.emissiveMap = item.material.map ;
                        }

                    }

                    buildNoPositionMap.forEach((value, key) => {
                        //todo
                        const { status, floor } = json.data.find(item => item.name === key + "#")

                        this.addBuildingTag(key, value[0], value[1], value[2], status, floor)
                    })

                    //渲染标签
                    // console.log("callFinish", callFinish)
                    if (this.callFinish != null) {
                        this.callFinish()
                    }

                }).catch(() => {

                    this.callFinish && this.callFinish()
                })
            }
            const { groupArr } = this
            let numStrArr
            let boxInnerCenter, h, topCenter
            let buildTopFloors = new Map //楼号-最高层数的散列表
            for (let a = 0; a < groupArr.length; a++) {
                if (groupArr[a].name.search("-") != -1) {
                    numStrArr = correctArr(groupArr[a].name.replace("_","").split("-"))
                    if (buildTopFloors.get(numStrArr[0]) == null) {
                        buildTopFloors.set(numStrArr[0], numStrArr[3])
                    } else {
                        if (parseInt(numStrArr[3]) > parseInt(buildTopFloors.get(numStrArr[0]))) {
                            buildTopFloors.set(numStrArr[0], numStrArr[3])
                        }
                    }
                }
            }
            buildUnitMap = new Map()
            buildTopFloors.forEach(function (value, key) {
                buildUnitMap.set(key, [])
            })
            for (let a = 0; a < groupArr.length; a++) {
                if (groupArr[a].name.search("-") != -1) {
                    numStrArr = correctArr(groupArr[a].name.replace("_","").split("-"))
                    if (numStrArr[3] == "1") {
                        if (buildUnitMap.get(numStrArr[0]).indexOf(numStrArr[1] + "-" + numStrArr[2]) == -1) {
                            buildUnitMap.get(numStrArr[0]).push(numStrArr[1] + "-" + numStrArr[2])
                        }
                    }
                }
            }



            buildUnitMap.forEach(function (value) {
                value.sort()
            })
            var peakArrMap = new Map() //楼号-顶楼各群组中心点数组的散列表
            buildTopFloors.forEach(function (value, key) {
                peakArrMap.set(key, [])
            })

            for (var a = 0; a < groupArr.length; a++) {
                if (groupArr[a].name.search("-") != -1) {
                    numStrArr = correctArr(groupArr[a].name.replace("_","").split("-"))
                    if (numStrArr[3] == buildTopFloors.get(numStrArr[0])) { //最高层的某个群组
                        groupArr[a].children[0].geometry.computeBoundingSphere()
                        boxInnerCenter = groupArr[a].children[0].geometry.boundingSphere.center
                        peakArrMap.get(numStrArr[0]).push({
                            x: groupArr[a].position.x + boxInnerCenter.x,
                            y: groupArr[a].position.y + boxInnerCenter.y,
                            z: groupArr[a].position.z + boxInnerCenter.z
                        })
                    }
                }
            }

            var buildNoPositionMap = new Map() //楼号-楼号标签位置的散列表

            peakArrMap.forEach(function (value, key) {
                var x = 0, y = 0
                var peakArr = value
                for (h = 0; h < peakArr.length; h++) {
                    x += peakArr[h].x;
                    y += peakArr[h].y;
                }
                topCenter = [x / peakArr.length / 39.4, y / peakArr.length / 39.4, peakArr[0].z / 39.4]
                buildNoPositionMap.set(key, topCenter)
            })





        })

    }
    init(loadUrl, colorUrl, term, callFinish, debug = false, longitude, latitude) {
        this.loadUrl = loadUrl
        this.colorUrl = colorUrl
        this.initTerm = term
        this.callFinish = callFinish
        this.debug = debug
        this.longitude = longitude
        this.latitude = latitude
        /**
             * 创建场景对象Scene
             */
        // this.scene.autoUpdate = true
        const { scene } = this
        /**
         * 创建网格模型
         */
        // 辅助坐标系 
        if (debug) {
            var axes = new THREE.AxesHelper(1000);
            scene.add(axes);
        }

        this.loader = new ColladaLoader();



        this._loadDae(loadUrl)

        //添加底板
        let planeGeometry = new THREE.PlaneGeometry(3000, 3000);
        let planeMaterial = new THREE.MeshStandardMaterial({ color: 0xcccccc });
        // 关闭deptchTest，使该材质无视渲染顺序，必定被渲染（防止重叠闪烁）
        planeMaterial.depthTest = false
        planeMaterial.depthWrite = true
        this.plane = new THREE.Mesh(planeGeometry, planeMaterial);
        // plane.position.z = 2
        // plane.rotation.x = 0;
        // plane.position.y = 0;

        //设置平面需要接收阴影
        this.plane.receiveShadow = true;
        scene.add(this.plane);

        if (debug) {
            this.stat = new Stat()

            //添加到document中
            document.body.append(this.stat.dom)
        }


        /**
         * 光源设置
         */
        // 第二个参数为光照强度，2倍
        if (!this.light) {
            this.light = new THREE.DirectionalLight(0xFFFFFF, 0.9)
            const { light } = this
            light.position.set(600, 600, 600); //点光源位置
            light.castShadow = true;//开启阴影
            light.shadow.mapSize.width = 4096; //阴影贴图宽度设置为2048像素
            light.shadow.mapSize.height = 4096; //阴影贴图高度设置为2048像素
            light.shadow.radius = 0;
            //Set up shadow properties for the light
            light.shadow.camera.near = 100;
            light.shadow.camera.far = 3000;
            light.shadow.camera.left = -300;
            light.shadow.camera.right = 300;
            light.shadow.camera.top = 300;
            light.shadow.camera.bottom = -300;

            // light.shadow.bias = 0.0001
            // light.shadow.color = '#ff0000'

            scene.add(light);
        }

        // //环境光 由于环境光作用于所有的物体，所有的材质，所以环境光是没有方向的，也无法产生阴影效果。
        if (!this.ameLight) {
            this.ameLight = new THREE.AmbientLight(0xffffff, 0.4)
            scene.add(this.ameLight);
        }


        if (debug) {
            const helper = new THREE.CameraHelper(this.light.shadow.camera);
            scene.add(helper);
        }



        /**
         * 相机设置
         */

        var k = width / height; //窗口宽高比
        var s = 300; //三维场景显示范围控制系数，系数越大，显示的范围越大
        //创建相机对象
        // this.camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 5000);
        this.camera = new THREE.PerspectiveCamera(this.fov, width / height, this.near, this.fear);
        const { camera } = this
        camera.position.set(400, 0, 500); //设置相机位置
        camera.up.x = 0;
        camera.up.y = 0;
        camera.up.z = 1; //z轴向上
        camera.lookAt(scene.position); //设置相机方向(指向的场景对象)

        /**
         * 创建渲染器对象
         */
        this.renderer = new THREE.WebGLRenderer({
            antialias: true, // true/false表示是否开启反锯齿
            alpha: true, // true/false 表示是否可以设置背景色透明
            logarithmicDepthBuffer: true,
            checkShaderErrors: false, //关闭检查提高性能
        });
        this.renderer.shadowMap.enabled = true
        // this.renderer.shadowMap.autoUpdate = true
        this.renderer.shadowMap.needsUpdate = true
        this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
        this.renderer.setSize(width, height);//设置渲染区域尺寸
        this.renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
        //关闭之后，修改模型（颜色）必须手动reset
        this.renderer.info.autoReset = false;
        this.renderer.setScissorTest(false)
        this.renderer.setPixelRatio(window.devicePixelRatio);//设置canvas的像素比为当前设备的屏幕像素比，避免高分屏下模糊
        this.renderer.physicallyCorrectLights = false

        document.getElementById('app').appendChild(this.renderer.domElement); //body元素中插入canvas对象


        this.controls = new OrbitControls(camera, this.renderer.domElement);//创建控件对象
        //设置相机角度
        //上下翻转的最大角度
        this.controls.maxPolarAngle = 1.4;
        //上下翻转的最小角度
        this.controls.minPolarAngle = 0;
        //是否允许缩放
        this.controls.enableZoom = true;

        this.controls.enableDamping = true
        this.controls.maxZoom = 10
        this.controls.minZoom = 0.8

        //添加标签
        //初始化CSS2渲染器
        this.labelRenderer = new CSS2DRenderer();
        this.labelRenderer.setSize(width, height);
        this.labelRenderer.domElement.style.position = 'absolute';
        this.labelRenderer.domElement.style.pointerEvents = 'none'
        this.labelRenderer.domElement.style.boxSizing = 'border-box'
        this.labelRenderer.domElement.style.top = 0;
        // document.body.appendChild(labelRenderer.domElement);
        // console.log(labelRenderer.domElement)

        document.body.appendChild(this.labelRenderer.domElement);

        // console.log('canvas', $('canvas')[0])
        // $('canvas')[0].addEventListener('mousewheel', this.mousewheel, false);
    }
    getXY(rad, r) {
        let angle = rad * 1.0 / Math.PI * 180
        let y = Math.abs(Math.sin(rad)) * r
        let x = Math.abs(Math.cos(rad)) * r

        if (angle < 90) {
            return [-x, y]
        } else if (angle < 180) {
            return [x, y]
        } else if (angle < 270) {
            return [x, -y]
        } else {
            return [-x, -y]
        }
    }

    _getSunSkyColorRgb(rad) {
        const C = 8.0;
        let r, g, b
        let res = {}
        // set sun
        r = (255 - C / Math.sqrt(1 - Math.cos(rad)) * 0.03);
        g = (255 - C / Math.sqrt(1 - Math.cos(rad)) * 0.75);
        b = (255 - C / Math.sqrt(1 - Math.cos(rad)) * 0.97);
        res.sun = { r, g, b }

        // set sky
        r = (255 - C / Math.sqrt(1 - Math.cos(rad)) * 0.73);
        g = (255 - C / Math.sqrt(1 - Math.cos(rad)) * 0.05);
        b = (255 - C / Math.sqrt(1 - Math.cos(rad)) * 0.07);
        res.sky = { r, g, b }
        return res;
    }
    calcSunAngleRad(date) {
        // 获取当前时间
        // console.log(date)
        let year = date.getFullYear()
        let month = date.getMonth()
        let day = date.getDate()
        // console.log('calc', year, month ,day)
        let hour = date.getHours()
        let mim = date.getMinutes()
        let second = date.getSeconds()

        // 获取儒略日
        let jd = sun.getJulianDay(year, month + 1, day);

        // 经纬度
        let latitude = this.latitude
        let longitude = this.longitude

        // 时区
        let tz = 8

        // 今天已过了多少分钟
        let tl = sun.getLocalTime(hour, mim, second)

        // 使用时间、时区修正的分钟数
        let t = jd + tl / 1440.0 - tz / 24.0

        // 世纪数
        t = sun.calcTimeJulianCent(t)
        // console.log('t', t, tl)

        //返回 [高度角，方位角]
        //方位角：正北 开始 0 ~ 360
        // console.log(sun.calcelevation(t, tl, latitude, longitude, tz), sun.calcazimuth(t, tl, latitude, longitude, tz, 0))
        return [(sun.calcelevation(t, tl, latitude, longitude, tz) - 5) / 180.0 * Math.PI,
        sun.calcazimuth(t, tl, latitude, longitude, tz, 0) / 180.0 * Math.PI
        ]
    }

    //speed 时间倍数：
    //我们要的是 1s 走 10min（一格progress），即 600倍
    _render(date, isRun = false, speed, cellChangeCall) {
        // console.log("_render", date.getMonth(), date.getDate(), date.getHours(), date.getMinutes())
        this.lastDate = date
        //10min钟通知一次，及progress前进一个单位
        const cellMinute = 10


        //getElapesedTime 获取运行的总时长，单位秒
        if (!date)
            date = new Date()
        //获取当前太阳高度角 方位角
        let r = 2000
        let [alt, azi] = this.calcSunAngleRad(date)
        //根据高度角计算太阳高度

        let z = r * Math.sin(alt)

        //根据方位角计算x,y
        let [x, y] = this.getXY(azi, r * Math.cos(alt))
        this.light.position.x = x
        this.light.position.y = y
        this.light.position.z = z

        //注意刷新时机
        this.controls.update()
        if (this.stat)
            this.stat.update()

        this.renderer.render(this.scene, this.camera);//执行渲染操作
        this.labelRenderer.render(this.scene, this.camera)

        //指南针

        //只考虑xoy平面，本项目x轴为南，y轴为东，即x轴负方向为正北方向
        //取与相机相反方向的向量，即目光所在的向量
        let dir = new THREE.Vector3(-this.camera.position.x, -this.camera.position.y, 0).normalize();

        let theta = Math.atan2(-dir.y, -dir.x);
        // console.log(this.camera.position)
        //指南针旋转
        $('#guide-wrap .compass').css({ 'transform': 'translate(-50%, -50%) rotate(' + THREE.Math.radToDeg(theta) + 'deg)' });


        if (isRun) {

            let cur = Math.floor(date.getMinutes() / cellMinute)
            // console.log(cur)
            if (cur != this._flag) {
                this._flag = cur
                if (cellChangeCall != null) {
                    cellChangeCall(date.getHours() * (60 / cellMinute) + cur)
                }
            }
            if (this.clock == null) {
                this.clock = new THREE.Clock()
            }
            let target = new Date(date.getTime() + Math.ceil(this.clock.getDelta() * 1000 * speed))
            if (date.getHours() < this.start || date.getHours() >= this.end) {
                //从头开始帧动画
                target = new Date(date.getFullYear(), date.getMonth(), date.getDate(), this.start)
                // console.log('从头开始帧动画', target.getHours())
            }
            this._frameHandler = requestAnimationFrame(() => this._render(target, true, speed, cellChangeCall));
        } else { //不run，时间不变
            this._frameHandler = requestAnimationFrame(() => this._render(date, false));
        }

    }
    renderPlayer(fromDate, speed, cellChangeCall) {
        this.date = fromDate
        this.cancelAnim()
        this.clock = null
        this._render(fromDate, true, speed, cellChangeCall)
    }
    renderAtTime(date) {
        this.lastDate = date
        this.cancelAnim()
        this.clock = null
        this._render(date, false)
    }
    stopRenderPlayer() {
        this.cancelAnim()
        this.renderAtTime(this.lastDate)
    }
    cancelAnim() {
        if (this._frameHandler != null) {
            window.cancelAnimationFrame(this._frameHandler)
            this._frameHandler = null
        }
    }

    //添加标签文字材质
    addBuildingTag(text, x, y, z, status, lou) {
        let tagDiv = document.createElement('div')//创建div容器
        let maxF = 12, minF = 10
        tagDiv.className = 'building_tag'
        tagDiv.innerHTML = `<span style="font-size: ${maxF}px;">${text}</span>#`
        if (status) {
            tagDiv.innerHTML += `${status}`
        }
        if (lou) {
            tagDiv.innerHTML += `&nbsp;<span style="font-size:  ${maxF}px;">${lou}</span>F`
        }
        tagDiv.style.pointerEvents = 'all';
        tagDiv.style.color = '#111'
        tagDiv.style.boxSizing = 'border-box'
        tagDiv.style.fontSize = minF + 'px'
        tagDiv.style.borderRadius = '7px'
        tagDiv.style.lineHeight = '14px'
        tagDiv.style.paddingLeft = '2px'
        tagDiv.style.paddingRight = '2px'
        tagDiv.style.border = '1px solid #111'
        tagDiv.style.verticalAlign = 'baseline'
        tagDiv.style.backgroundColor = fillStyleMap[status] + 'ee'
        if (!status) {
            tagDiv.style.backgroundColor = '#FFFFFFEE'
        }
        tagDiv.addEventListener('click', () => {
            // controls.reset()
            let _x = -y - this.dx
            let _y = x - this.dy
            let _z = z + 20
            let d = Math.sqrt(_x * _x + _y * _y)
            let r = Math.sqrt(d * d + _z * _z)


            let dis = 200

            let newD = (r + dis) / r * d


            let newX = newD / d * _x
            let newY = newD / d * _y

            let newZ = Math.sqrt(newD * newD + (r + dis) * (r + dis))
            this.camera.position.set(newX, newY, _z + 10)

        })

        let pointLabel = new CSS2DObject(tagDiv);

        pointLabel.position.set(-y - this.dx, x - this.dy, z + 20);


        this.scene.add(pointLabel)

    }

    //鼠标滑轮-鼠标上下滑轮实现放大缩小效果

    mousewheel(e) {
        console.log(e)
        e.preventDefault();

        //e.stopPropagation();

        if (e.wheelDelta) {  //判断浏览器IE，谷歌滑轮事件
            if (e.wheelDelta > 0) { //当滑轮向上滚动时
                this.fov -= (this.near < this.fov ? 1 : 0);
            }

            if (e.wheelDelta < 0) { //当滑轮向下滚动时
                this.fov += (this.fov < this.far ? 1 : 0);
            }

        } else if (e.detail) {  //Firefox滑轮事件
            if (e.detail > 0) { //当滑轮向上滚动时
                this.fov -= 1;
            }

            if (e.detail < 0) { //当滑轮向下滚动时
                this.fov += 1;
            }
        }

        console.info('camera.fov:' + this.camera.fov);

        console.info('camera.x:' + this.camera.position.x);

        console.info('camera.y:' + this.camera.position.y);

        console.info('camera.z:' + this.camera.position.z);

        //改变fov值，并更新场景的渲染

        this.camera.fov = this.fov;

        this.camera.updateProjectionMatrix();

        this.renderer.render(this.scene, this.camera);

        //updateinfo();

    }

    //重置恢复
    reset() {
        this.camera.position.set(400, 0, 500)
        this.controls.reset()
    }
}

